

#include "../app_manager.h"
#include "../inc/app_manager_fs.h"
#if APP_MANAGER_PLATFORM_ESP
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#endif

#if APP_MANAGER_LIB_ENABLE

#if (APP_MANAGER_SUPPORT_RTOS && APP_MANAGER_PLATFORM_ESP)

static SemaphoreHandle_t mutex_handle;

static void take_key()
{
    xSemaphoreTake(mutex_handle, portMAX_DELAY);
}

static void give_key()
{
    xSemaphoreGive(mutex_handle);
}

#endif

#if APP_MANAGER_MALLOC_FREE_USE_CLIB == false

void *(*malloc_mem)(size_t size) = NULL;
void (*free_mem)(void *ptr) = NULL;

/**
 * @brief 注册malloc和free回调函数
 *
 * @param malloc
 * @param free
 */
app_manager_ret_t app_manager_register_malloc_free_cb(void *(*malloc_cb)(size_t size), void (*free_cb)(void *ptr))
{
    malloc_mem = malloc_cb;
    free_mem = free_cb;
    return APP_MANAGER_SUCCESS;
}
#else
#define malloc_mem malloc
#define free_mem free
#endif

void *app_manager_malloc(size_t size)
{
    return malloc_mem(size);
}
void app_manager_free(void *ptr)
{
    free_mem(ptr);
}

#if APP_MANAGER_SUPPORT_RTOS
app_manager_mutex_cb_t app_manager_mutex_cb;
#if APP_MANAGER_PLATFORM_ESP
static app_manager_ret_t app_manager_register_mutex_cb(app_manager_mutex_cb_t *cb)
#else
app_manager_ret_t app_manager_register_mutex_cb(app_manager_mutex_cb_t *cb)
#endif
{
    if (cb->mutex_get_cb == NULL || cb->mutex_give_cb == NULL)
        return APP_MANAGER_ERROR;
    app_manager_mutex_cb.mutex_get_cb = cb->mutex_get_cb;
    app_manager_mutex_cb.mutex_give_cb = cb->mutex_give_cb;
    return APP_MANAGER_SUCCESS;
}
#endif

app_manager_ret_t app_manager_init()
{

#if APP_MANAGER_SUPPORT_RTOS && APP_MANAGER_PLATFORM_ESP
    mutex_handle = xSemaphoreCreateMutex();
    app_manager_mutex_cb_t cfg1 = {
        .mutex_get_cb = take_key,
        .mutex_give_cb = give_key};
    app_manager_register_mutex_cb(&cfg1);
#endif

#if APP_MANAGER_MALLOC_FREE_USE_CLIB == false
    if (malloc_mem == NULL || free_mem == NULL)
    {
        app_manager_mutex_cb.mutex_give_cb();
        return APP_MANAGER_MALLOC_FREE_ERROR;
    }
#endif

#if APP_MANAGER_ENABLE_APP_UNINSTALL
    app_manager_fs_init();
#endif

    app_manager_register();

    return APP_MANAGER_SUCCESS;
}

app_manager_ret_t app_manager_task(app_manager_task_t task, void *arg)
{
    app_manager_ret_t ret = APP_MANAGER_SUCCESS;
#if APP_MANAGER_SUPPORT_RTOS
    app_manager_mutex_cb.mutex_get_cb();
#endif

    if (task == APP_MANAGER_KILL_ALL)
    {
        for (size_t i = 0; i < app_manager_get_installed_number(); i++)
        {
            app_register_t *app = app_manager_get_installed_app(i, NULL);
            app->kill_process(NULL);
        }
        goto give_mutex;
    }
    if (task == APP_MANAGER_KILL_ONE)
    {
        app_register_t *app = app_manager_get_installed_app(0, (const char *)arg);

        if (app == NULL)
        {
            ret = APP_MANAGER_NAME_NONE;
            goto give_mutex;
        }
        else
            app->kill_process(NULL);
        goto give_mutex;
    }
    if (task == APP_MANAGER_DEL_UI_ALL)
    {
        for (size_t i = 0; i < app_manager_get_installed_number(); i++)
        {
            app_register_t *app = app_manager_get_installed_app(i, NULL);
            if (app != app_manager_get_forground_app())
                app->destroy_ui(NULL);
        }
        goto give_mutex;
    }
    if (task == APP_MANAGER_DEL_UI)
    {
        app_register_t *app = app_manager_get_installed_app(0, (const char *)arg);
        if (app == app_manager_get_forground_app())
        {
            ret = APP_MANAGER_ERROR;
            goto give_mutex;
        }
        if (app == NULL)
        {
            ret = APP_MANAGER_NAME_NONE;
            goto give_mutex;
        }
        else
            app->destroy_ui(NULL);
        goto give_mutex;
    }
    if (task == APP_MANAGER_REGISTER_APP)
    {
        ret = app_manager_register_app((app_register_t *)arg);
        goto give_mutex;
    }

#if APP_MANAGER_ENABLE_APP_UNINSTALL
    if (task == APP_MANAGER_SAVE_DATA)
    {
        ret = app_manager_fs_save_change_data();
        goto give_mutex;
    }
#endif

give_mutex:
#if APP_MANAGER_SUPPORT_RTOS
    app_manager_mutex_cb.mutex_give_cb();
#endif

    return ret;
}

#endif // #if APP_MANAGER_LIB_ENABLE